package com.spring.bean;


import com.spring.enums.ScopeType;
import com.spring.util.StringUtils;
import lombok.Data;

import java.lang.reflect.Method;


/**
 * 3种 创建对象方式：
 *
 * 1. beanClass 就是 bean 自己的类，该对象可以直接无参数反射构造出来 ，需要  beanName  beanClass  scope  3个核心参数即可
 *
 * 2. beanClass 就是 bean 自己的类，但不能直接反射创建，需要调用  某个对象的某个方法 来返回(@Bean)，需要  beanName  beanClass  scope   factoryBeanName   factoryMethodName
 *
 * 3. beanClass 不是 bean 自己的类 而是工厂类，  bean 不能直接创建
 * 需要先创建工厂，  调用工厂的方法 getObject() 来创建
 *
 * 需要 beanName  beanClass  scope  factoryBeanName   constructorArgumentValues
 *
 *
 * 判断是不是工厂bean, 先检查有没有factoryBeanName   没有就是方式1   有就再检查 beanClass 是否实现 FactoryBean 接口，没有实现 就是 方式2 ，有实现则方式3
 */


@Data
public class BeanDefinition {
	/**
	 * bean 名字
	 */
	private String beanName;
	
	/**
	 * 普通bean , 直接用 beanClass 反射实例化对象
	 * 工厂bean ，用 factoryBeanName 找到工厂对象，调用 factoryMethodName 对应的 无参方法 创建对象
	 */
	private Class<?> beanClass;
	
	/**
	 * 作用域类型, SINGLE 或 PROTOTYPE
	 */
	private ScopeType scope;
	
	
	/**
	 * 工厂bean 名字   @Bean 才有这种
	 *
	 * 如果有的话， 就应当从容器中获取 这个bean ,然后反射调用工厂方法
	 */
	private String factoryBeanName;
	/**
	 * 工厂bean 方法
	 */
	private String factoryMethodName;
	
	/**
	 * bean 自己初始化方法
	 */
	private String initMethodName;
	
	/**
	 * bean 自身的销毁方法
	 */
	private String destroyMethodName;
	
	// 工厂方法的参数类型
	private Class<?>[] parameterTypes;
	
	// 构造参数类型
	private Class<?>[] constructorArgumentValues;
	
	
	/**
	 * 针对配置类的定义
	 */
	private boolean resolved = false;
	
	public BeanDefinition() {
	}
	
	public BeanDefinition(Class<?> beanClass) {
		this(StringUtils.toLowerFirstCase(beanClass.getSimpleName()), beanClass);
	}
	
	public BeanDefinition(String beanName, Class<?> beanClass) {
		this.beanName = beanName;
		this.beanClass = beanClass;
		this.scope = ScopeType.SINGLE;
	}
	
	/**
	 * 给@Bean 方式用的
	 *
	 * @param beanName          返回的bean 名称
	 * @param factoryBeanName   工厂对象bean名称
	 * @param factoryMethodName 工厂方法 method
	 */
	
	@Deprecated
	public BeanDefinition(String beanName, String factoryBeanName, String factoryMethodName, Method factoryMethod) {
		this.beanName = beanName;
		this.factoryBeanName = factoryBeanName;
		this.factoryMethodName = factoryMethodName;
		
		this.scope = ScopeType.SINGLE;
	}
	
	
	public boolean isSingleton() {
		return this.scope == ScopeType.SINGLE;
	}
	
	/**
	 * factoryBeanName 不能为null 且 不为空字符串时，才是工厂bean
	 */
	public boolean isFactoryBean() {
		return StringUtils.isNotEmpty(factoryBeanName) && StringUtils.isNotEmpty(factoryMethodName);
	}
}
